package lzc.encrypt.rtree;

import com.github.davidmoten.rtree.Entry;
import com.github.davidmoten.rtree.RTree;
import com.github.davidmoten.rtree.geometry.Rectangle;
import lzc.encrypt.IPPE;
import lzc.encrypt.encryption.DataVector;
import lzc.encrypt.encryption.Parameter;
import lzc.encrypt.encryption.SearchVector;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 加密R树
 *
 * @author 蓝色的三明治
 * @date 2024/10/26
 */
public class ERTree {
    // 明文的矩形R树
    private RTree<String, Rectangle> tree = RTree.maxChildren(4).create();

    private EncryptionRecord record = new EncryptionRecord();

    /**
     * 加密R树
     */
    public void encrypt() {
        // 将加密状态设置为加密，从而启动R树的加密
        isEncrypted();

        // 使用根节点的MBR来搜索R树，从而遍历R树的每个结点，实现R树所有结点的加密
        Rectangle root = tree.root().get().geometry().mbr();
        List<Integer> result = search(root);
        System.out.println("加密完成：" + result);
    }

    /**
     * 打印R树的明文内容
     */
    public void display() {
        System.out.println(tree.asString());
    }

    /**
     * 获取字符串格式的R树明文内容
     *
     * @return {@link String}
     */
    public String asString() {
        return tree.asString();
    }

    /**
     * 向R树中添加矩形对象
     *
     * @param id        对象的id
     * @param rectangle 矩形对象
     */
    public void add(String id, Rectangle rectangle) {
        tree = tree.add(id, rectangle);
    }

    /**
     * 搜索加密R树
     *
     * @param searchRectangle 搜索范围
     * @return {@link List}<{@link Integer}> 搜索结果的id列表
     */
    public List<Integer> search(Rectangle searchRectangle) {
        // 对搜索范围加密并记录
        recordSearchRectangle(searchRectangle);

        // 将当前的加密记录更换为即将进行搜索的R树的加密记录
        currentRecord = record;

        List<Entry<String, Rectangle>> searchResult = tree.search(searchRectangle).toList().toBlocking().single();

        List<Integer> result = new ArrayList<>();
        for (Entry<String, Rectangle> entry : searchResult) {
            result.add(Integer.valueOf(entry.value()));
        }

        return result;
    }

    /**
     * 设置R树的IPPE加密参数
     *
     * @param parameter IPPE加密参数
     */
    public void setParameterForRTree(Parameter parameter) {
        record.parameterForRTree = parameter;
    }

    /**
     * 设置R树的加密状态为“加密”
     */
    public void isEncrypted() {
        record.ifEncrypted = true;
    }

    /**
     * 设置R树的加密状态为“不加密”
     */
    public void isNotEncrypted() {
        record.ifEncrypted = false;
    }

    /**
     * 记录搜索范围并对其加密
     *
     * @param rectangle 搜索范围
     */
    private void recordSearchRectangle(Rectangle rectangle) {
        System.out.println("test");
        record.recordSearchRectangle(rectangle);
    }

    /**
     * 加密记录，用于加密MBR相交计算
     * 每个R树都有一个加密记录
     *
     * @author 蓝色的三明治
     * @date 2024/10/26
     */
    private class EncryptionRecord {
        public boolean ifEncrypted = false;// R树的加密状态，true表示加密，false表示未加密
        private Map<Rectangle, DataVector[]> encryptionMap = new HashMap<>();// 记录MBR和对应的加密数据向量
        private SearchVector[] encryptedSearchRectangle;// 记录搜索范围对应的加密搜索向量
        private Parameter parameterForRTree;// R树的IPPE加密参数

        /**
         * 记录搜索范围并对其加密
         *
         * @param rectangle 搜索范围
         */
        public void recordSearchRectangle(Rectangle rectangle) {
            encryptedSearchRectangle = parameterForRTree.encryptSearchVector(rectangle);
        }

        /**
         * 加密状态下计算搜索范围和当前结点MBR是否相交
         *
         * @param rectangle 当前结点MBR
         * @return boolean true表示搜索范围和当前结点的范围相交，false表示搜索范围和当前结点的范围不相交
         */
        public boolean intersects(Rectangle rectangle) {
            DataVector[] dataVectors = encryptionMap.get(rectangle);
            if (dataVectors == null) {
                dataVectors = parameterForRTree.encryptDataVector(rectangle);
                encryptionMap.put(rectangle, dataVectors);
            }
            return parameterForRTree.check(dataVectors, encryptedSearchRectangle);
        }
    }

    // 以下为静态变量和静态方法，用于公用的加密R树搜索算法

    private static EncryptionRecord currentRecord;// 当前正在进行加密计算的R树的加密记录

    /**
     * 设置当前正在进行加密计算的R树的加密记录
     *
     * @param currentRecord 当前正在进行加密计算的R树的加密记录
     */
    public static void setEncryptionRecord(EncryptionRecord currentRecord) {
        ERTree.currentRecord = currentRecord;
    }

    /**
     * 加密状态下计算搜索范围和当前结点MBR是否相交
     *
     * @param rectangle 当前结点MBR
     * @return boolean true表示搜索范围和当前结点的范围相交，false表示搜索范围和当前结点的范围不相交
     */
    public static boolean intersects(Rectangle rectangle) {
        return currentRecord.intersects(rectangle);
    }

    /**
     * 获取R树的加密状态
     *
     * @return boolean R树的加密状态，true表示加密，false表示未加密
     */
    public static boolean ifEncrypted() {
        return currentRecord.ifEncrypted;
    }

}
